home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS26.ADF / SoundScape / LatticeExamples / tx.c < prev    next >
C/C++ Source or Header  |  1989-01-26  |  13KB  |  461 lines

  1. /*      TX.C
  2.  
  3.         (c) 1987 Todor Fay 
  4.  
  5. */ 
  6.  
  7. #include "exec/types.h" 
  8. #include "exec/exec.h" 
  9. #include "hardware/custom.h" 
  10. #include "hardware/cia.h" 
  11. #include "exec/interrupts.h" 
  12. #include "exec/memory.h" 
  13. #include "hardware/intbits.h" 
  14. #include "libraries/dos.h" 
  15. #include "intuition/intuition.h"
  16. #include "soundscape.h" 
  17.  
  18. extern struct CIA ciaa;
  19. extern struct Custom custom;
  20.  
  21. /*    The state structure for this module has just the
  22.       file name for saving a TX81Z (or DX21/27/100) voice.  
  23.       Whenever an environment save command (SAVESTATE) 
  24.       occurs, the file that the voice was saved in is 
  25.       returned here.  When an environment load command 
  26.       (LOADSTATE) happens, the file that is given here 
  27.       will be loaded by this module.
  28. */
  29.  
  30. struct SynthState { 
  31.     long length; 
  32.     char filename[70]; 
  33. }; 
  34.  
  35. /*    Initialise the file name as empty. */
  36.  
  37. static struct SynthState synthstate = { 70,0, }; 
  38.  
  39. /*    The port id for this port. */
  40.  
  41. static short thisport;
  42.  
  43. /*    The icon in the Patch Panel. */
  44.  
  45. UWORD tx81zdata[] = {        /* 32 x 12 */ 
  46. 0,        0,        
  47. 0,        0,        
  48. 0,        0,        
  49. 0,        0,        
  50. 0,        0,        
  51. 0,        0,        
  52. 0,        0,        
  53. 8078,     32752,        
  54. 12486,    448,        
  55. 8070,     1792,        
  56. 12486,    7168,        
  57. 8079,     32752,        
  58. 16383,    57344,        
  59. 224,      0,        
  60. 231,      28672,        
  61. 227,      57344,        
  62. 225,      49152,        
  63. 227,      57344,        
  64. 231,      28672,        
  65. 0,        32752,        
  66. 0,        448,        
  67. 0,        1792,        
  68. 0,        7168,        
  69. 0,        32752,        
  70. };
  71.  
  72. struct Image tx81zimage = { 0,0,32,12,2,tx81zdata,3,0,0 };
  73.  
  74. /*    We need to be able to display messages to the user.
  75.       For example, "Sending the voice...".  Two
  76.       routines handle this.  Onmessage opens a window
  77.       and displays the given strings.  Offmessage
  78.       closes that window.  Here is the window declaration.
  79. */
  80.  
  81. struct NewWindow NewWindowStructure = {
  82.         134,35,
  83.         336,66,
  84.         0,1,
  85.         NULL,
  86.         ACTIVATE,
  87.         NULL,
  88.         NULL,
  89.         "TX81Z/DX21/DX27/DX100 Librarian",
  90.         NULL,
  91.         NULL,
  92.         5,5,
  93.         640,200,
  94.         WBENCHSCREEN
  95. };
  96.  
  97. struct Window *messagewindow = 0;
  98.  
  99. void onmessage(string1,string2) 
  100.  
  101. /*      Opens a window and prints the message.   
  102.         Window is closed by offmessage(). 
  103. */ 
  104.  
  105. char string1[], string2[];
  106.  
  107.     static struct IntuiText text = { 2,0,JAM2,0,0,0,0, };
  108.     messagewindow = (struct Window *) 
  109.         OpenWindow(&NewWindowStructure);
  110.     if (messagewindow) {
  111.         text.IText = string1; 
  112.         PrintIText(messagewindow->RPort,&text,20,20);
  113.         if (string2) {
  114.             text.IText = string2; 
  115.             PrintIText(messagewindow->RPort,&text,20,30); 
  116.         }
  117.     }
  118.  
  119. void offmessage() 
  120.  
  121. /*      This just closes messagewindow if it is open. */
  122.  
  123.     if (messagewindow) {
  124.         CloseWindow(messagewindow); 
  125.     }
  126.     messagewindow = 0; 
  127. }   
  128.   
  129.  
  130. opencode(direction) 
  131.  
  132. /*      Routine to open this modules's port in the
  133.         direction specified. Always return TRUE
  134.         for success.
  135. */        
  136.  
  137. char direction; 
  138.  
  139.     return(1); 
  140.  
  141.  
  142. closecode(direction)
  143.  
  144. /*      Always close successfully. */
  145.  
  146. char direction; 
  147.  
  148.     return(1); 
  149.  
  150.  
  151. unsigned long processbyte(buffer,maxlength,midiindata) 
  152.  
  153. /*      When a data byte comes in, this routine is
  154.         called to process it.  Buffer is a pointer
  155.         to an array to store the data in.  Maxlength
  156.         is the size of that array.  Midiindata is
  157.         the data byte that just came in.
  158.         
  159.         The static variable sysexon keeps track of
  160.         whether we are currently reading a system
  161.         exclusive packet.  It is initialised to
  162.         FALSE (0). When a System Exclusive status
  163.         byte comes in, sysexon is set.  When the
  164.         end of the packet is reached, sysexon is
  165.         turned off again.
  166.  
  167.         The static variable length keeps track of 
  168.         where we are in the array.  It is not 
  169.         allowed to become greater than maxlength.
  170.  
  171.         Return 0 if still reading or about to
  172.         read the packet.  Return the length when
  173.         the packet end has been reached.
  174. */
  175.  
  176. register unsigned char *buffer;
  177. register unsigned long maxlength;
  178. register unsigned char midiindata; 
  179.  
  180.     static unsigned long length;
  181.     static char sysexon = 0; 
  182.           /*  Is this a status byte? */
  183.     if (midiindata & 0x80) { 
  184.           /*  MIDI real time event? */
  185.         if (midiindata >= CLOCK) { 
  186.             return(0); 
  187.         } 
  188.           /* End of packet? */
  189.         else if (sysexon) { 
  190.             sysexon = 0; 
  191.             buffer[length++] = midiindata;
  192.             return(length);
  193.         } 
  194.           /* Start of packet? */
  195.         else if (midiindata == SYSTEMX) { 
  196.             sysexon = 1;
  197.             length = 1;
  198.             *buffer = SYSTEMX;
  199.         } 
  200.     } 
  201.           /* Read data. */
  202.     else if (sysexon) { 
  203.         if (length < maxlength) { 
  204.             buffer[length++] = midiindata; 
  205.         }
  206.     } 
  207.     return(0); 
  208.  
  209.  
  210. unsigned long ReceiveSysEx(buffer,maxlength) 
  211.  
  212. /*      To receive a system exclusive buffer,
  213.         disable interrupts and poll the serial
  214.         port and mouse button.  Whenever a data
  215.         byte comes in, pass it to the processbyte
  216.         routine, which deals with is appropriately.
  217.         Once the packet is in, return the length.
  218. */
  219.  
  220. register char *buffer; 
  221. register unsigned long maxlength; 
  222.  
  223.     register unsigned char c; 
  224.     unsigned long length = 0;
  225.     Disable(); 
  226.     for (;;) { 
  227.         while (!(custom.serdatr & 0x4000)) {
  228.             if ((~ciaa.ciapra) & 0xC0) {
  229.                 Enable();
  230.                 return(0);
  231.             }
  232.         }
  233.         c = (unsigned char) custom.serdatr; 
  234.         custom.intreq = INTF_RBF;
  235.         if (length = processbyte(buffer,maxlength,c)) 
  236.             break; 
  237.     } 
  238.     Enable(); 
  239.     return(length); 
  240.  
  241.  
  242. void SendSysEx(buffer,length) 
  243.  
  244. /*      First, set the priority of this task to 
  245.         higher than the SoundScape packet router
  246.         so there is no danger of SoundScape sending
  247.         a MIDI packet at the same time.
  248.         
  249.         Then, send all the bytes in the buffer,
  250.         polling the buffer empty bit before 
  251.         sending each byte.
  252.  
  253.         When done, bring the priority back down.
  254. */
  255.  
  256. register char *buffer; 
  257. register unsigned long length;
  258.  
  259.     register long oldpri = SetTaskPri(FindTask(0),21); 
  260.     register unsigned long i; 
  261.     for (i=0; i<length; i++) { 
  262.         while (!(custom.serdatr & 0x2000)); 
  263.         custom.serdat = buffer[i] | 0x300; 
  264.     } 
  265.     SetTaskPri(FindTask(0),oldpri); 
  266.           
  267.  
  268. void dosomething(direction,filename) 
  269.  
  270. /*      This routine is called to either read
  271.         a voice from disk and send it
  272.         to the synth, or read a voice from
  273.         the synth and store it to disk.
  274.         
  275.         Direction is set if we are to
  276.         store a sound to disk, otherwise cleared.
  277.  
  278.         A filename may be given (the case for
  279.         environment loads and saves.) If
  280.         so, the variable filename will have
  281.         that file name in it.  If there is
  282.         no filename (filename[0] == 0), 
  283.         put up a requester with a call to
  284.         ReadFileName or WriteFileName.
  285.  
  286.         If saving a voice to disk, first
  287.         send a dump request to the synth.
  288.         Then read the system exclusive packet
  289.         that comes back.  There is a danger
  290.         that no synth is hooked up, or the
  291.         wrong data is returned.  If this happens,
  292.         the length of the data returned will not
  293.         be 101, so don't save it to file.
  294.  
  295.         If sending a new voice, just read
  296.         it from file and send the data.
  297. */
  298.  
  299. char direction;
  300. register char filename[]; 
  301.  
  302.     register long buffer; 
  303.     register long file; 
  304.     static unsigned char dumprequest[] = { 0xF0,0x43,0x20,0x03,0xF7};
  305.     long length; 
  306.     buffer = AllocMem(200,MEMF_PUBLIC); 
  307.     if (buffer) { 
  308.         if (direction) { 
  309.             if (!filename[0]) 
  310.                 WriteFileName(filename,"TX81Z/DX Voice","tx81zvoice"); 
  311.             if (filename[0]) { 
  312.                 onmessage("Getting a Voice... ",
  313.                     "Click mouse to abort");
  314.                 SendSysEx(dumprequest,5);
  315.                 length = ReceiveSysEx(buffer,200);
  316.                 offmessage(); 
  317.                 if (length == 101) {
  318.                     file = Open(filename,MODE_NEWFILE); 
  319.                     if (file) { 
  320.                         Write(file,&length,4); 
  321.                         Write(file,buffer,length); 
  322.                         Close(file); 
  323.                     }
  324.                 } 
  325.             } 
  326.         } 
  327.         else { 
  328.             if (!filename[0]) 
  329.                 ReadFileName(filename,"TX81Z/DX Voice","tx81zvoice");
  330.             if (filename[0]) { 
  331.                 file = Open(filename,MODE_OLDFILE); 
  332.                 if (file) { 
  333.                     Read(file,&length,4);
  334.                     if (length == 101) { 
  335.                         Read(file,buffer,length); 
  336.                         Close(file); 
  337.                         onmessage("Sending the Voice... ",0);
  338.                         SendSysEx(buffer,length); 
  339.                         offmessage(); 
  340.                     }
  341.                 } 
  342.             } 
  343.         } 
  344.         FreeMem(buffer,200); 
  345.     } 
  346.  
  347.   
  348. void editcode(direction,command,buffer) 
  349.  
  350. /*      This, the edit routine, is called under
  351.         five circumstances:
  352.  
  353.         USEREDIT:
  354.         The user clicked on either the left or right
  355.         icon in the patch panel.  Which icon is
  356.         determined by the variable direction.  Clear
  357.         the SynthState filename field so there is no
  358.         current filename and make a FunctionCall to 
  359.         dosomething(direction,synthstate.filename)
  360.         which will either load a sound or save
  361.         one.
  362.  
  363.         SETSTATE:
  364.         This occurs when another module wishes to
  365.         change the data in this module's state
  366.         structure.  Simply copy the passed buffer
  367.         into synthstate.
  368.  
  369.         GETSTATE:
  370.         Another module wishes to read the contents
  371.         of this module's state structure.  Simply
  372.         copy synthstate into the passed buffer.
  373.  
  374.         LOADSTATE:
  375.         Another module asks this module to load
  376.         files.  This ususally occurs in the
  377.         context of an environment load.  Once again,
  378.         a buffer is passed and the data from it
  379.         is copied into synthstate.  This should have the
  380.         name of the file to read and send to the
  381.         TX81Z.
  382.  
  383.         SAVESTATE:
  384.         Another module asks this module to save
  385.         files.  This usually occurs in the
  386.         context of an environment save. This
  387.         time, we get the sound from the TX81Z and
  388.         save it to disk, then return the file name,
  389.         so that can be stored in the environment 
  390.         file.
  391. */ 
  392.  
  393. char direction, command; 
  394. struct SynthState *buffer; 
  395.  
  396.     switch (command) { 
  397.         case USEREDIT : 
  398.             synthstate.filename[0] = 0; 
  399.             FunctionCall(dosomething,direction,synthstate.filename); 
  400.             break; 
  401.         case SETSTATE : 
  402.             movmem(buffer,&synthstate,sizeof(synthstate)); 
  403.             break; 
  404.         case GETSTATE : 
  405.             movmem(&synthstate,buffer,sizeof(synthstate)); 
  406.             break; 
  407.         case LOADSTATE : 
  408.             movmem(buffer,&synthstate,sizeof(synthstate)); 
  409.             FunctionCall(dosomething,0,synthstate.filename); 
  410.             movmem(&synthstate,buffer,sizeof(synthstate)); 
  411.             break; 
  412.         case SAVESTATE : 
  413.             FunctionCall(dosomething,1,synthstate.filename); 
  414.             movmem(&synthstate,buffer,sizeof(synthstate)); 
  415.             break; 
  416.     } 
  417.     buffer->length = 70; 
  418.   
  419. long SoundScapeBase, IntuitionBase, GfxBase;
  420.  
  421. /*      Here's the main program.  As always with a 
  422.         SoundScape module, open the SoundScape library
  423.         to get a handle on the routines, then close
  424.         it so it can be eventually closed by the 
  425.         program that opened it initially.
  426.         Create a midi port in the patch panel and
  427.         wait for it to be closed, then leave.
  428. */
  429.  
  430. void main() { 
  431.     IntuitionBase = OpenLibrary("intuition.library",0); 
  432.     GfxBase = OpenLibrary("graphics.library",0); 
  433.     SoundScapeBase = OpenLibrary("soundscape.library",0); 
  434.     if (SoundScapeBase) { 
  435.         CloseLibrary(SoundScapeBase); 
  436.         thisport = AddMidiPort(opencode,closecode,editcode,0, 
  437.             &tx81zimage,&tx81zimage,-1,"tx81z"); 
  438.         SetTaskPri(FindTask(0),-20); 
  439.         while (MidiPort(thisport)) Delay(100); 
  440.     } 
  441.     CloseLibrary(IntuitionBase); 
  442.     CloseLibrary(GfxBase); 
  443. }
  444.